package com.syh.jn.scm.infrastructure.repository.impl.downstream.purchase;


import cn.redscarf.commons.util.bean.ExtBeanUtils;
import cn.redscarf.commons.util.other.ExtAssert;
import cn.redscarf.commons.util.other.ExtStringUtils;
import cn.redscarf.commons.util.validator.ValidationUtils;
import cn.redscarf.commons.wrapper.Wrapper;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.syh.core.ddd.infrastructure.repository.AbstractAggregateRepository;
import com.syh.core.expction.DataModelException;
import com.syh.jn.scm.domain.downstream.entity.purchase.DownPurchaseOrder;
import com.syh.jn.scm.domain.downstream.entity.purchase.DownPurchaseOrderItem;
import com.syh.jn.scm.domain.downstream.repository.purchase.DownPurchaseOrderRepository;
import com.syh.jn.scm.dto.downstream.purchase.DonwPurchaseStatisticalAmountVo;
import com.syh.jn.scm.dto.downstream.purchase.DownPurchaseOrderItemVo;
import com.syh.jn.scm.dto.downstream.purchase.DownPurchaseOrderVo;
import com.syh.jn.scm.dto.supplier.sale.SaleStatisticalAmountVo;
import com.syh.jn.scm.exception.BusinessException;
import com.syh.jn.scm.infrastructure.repository.model.base.goods.GoodsBrandModel;
import com.syh.jn.scm.infrastructure.repository.model.base.goods.GoodsCategoryModel;
import com.syh.jn.scm.infrastructure.repository.model.base.goods.GoodsModel;
import com.syh.jn.scm.infrastructure.repository.model.sale.SaleOrderItemModel;
import com.syh.jn.scm.infrastructure.repository.model.sale.SaleOrderModel;
import com.syh.jn.scm.infrastructure.repository.utils.MybatisTemplate;
import com.syh.jn.scm.infrastructure.repository.utils.SQLAliasGenerateUtil;
import com.syh.jn.scm.infrastructure.wrapper.BaseResolve;
import com.syh.jn.scm.infrastructure.wrapper.ResolveToSQL;
import org.apache.ibatis.jdbc.SQL;
import org.springframework.stereotype.Repository;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * Date:2018/7/9
 * Author:Clown
 * 下游采购单仓储实现 todo;
 */
@Repository
public class DownPurchaseOrderRepositoryImpl extends AbstractAggregateRepository<DownPurchaseOrder, SaleOrderModel, Long> implements DownPurchaseOrderRepository {

  /**
   * 保存订单方法
   *
   * @param downPurchaseOrder
   * @return
   */
  @Override
  public Long add(DownPurchaseOrder downPurchaseOrder) {
    Long id = super.add(downPurchaseOrder);
    this.saveOrderItems(id, downPurchaseOrder.getItems());
    return id;
  }

  /**
   * 修改订单方法
   *
   * @param downPurchaseOrder
   */
  @Override
  public void update(DownPurchaseOrder downPurchaseOrder) {
    super.update(downPurchaseOrder);
    this.removeItem(downPurchaseOrder);
    this.saveOrderItems(downPurchaseOrder.getId(), downPurchaseOrder.getItems());
  }

  /**
   * 重载update方法选择是否更新订单项
   * @param order 更新的采购单
   * @param isUpdateItem false：不更新订单项 true：更新订单项
   * @return
   */
  @Override
  public void update(DownPurchaseOrder order, boolean isUpdateItem) {
    if (isUpdateItem) {
      this.update(order);
    } else {
      super.update(order);
    }
  }

  @Override
  public DownPurchaseOrder getById(Long id) {
    DownPurchaseOrder order = super.getById(id);
    if (order == null) {
      return order;
    }
    order.setItems(this.getItemsByOrderId(id));
    return order;
  }

  @Override
  public DownPurchaseOrderVo getKeyView(Serializable key) {
    DownPurchaseOrderVo vo = super.getKeyView(key);
    if(vo == null)
      throw new BusinessException("数据异常，采购单据不存在");
    vo.setItems(transformDownPurcharse(this.getItemsByOrderId(vo.getId())));
    return vo;
  }

  /**
   * 删除订单方法
   *
   * @param downPurchaseOrder
   */
  @Override
  public void remove(DownPurchaseOrder downPurchaseOrder) {
    super.removeById(downPurchaseOrder.getId());
    super.remove(downPurchaseOrder);
    this.removeItem(downPurchaseOrder);
  }

  /**
   * 根据商品id拿到订单明细
   *
   * @param goodsId
   * @return
   */
  @Override
  public DownPurchaseOrderItem getByGoodsId(Long goodsId,Long id) {
    StringBuffer hql = new StringBuffer();
    hql.append("from SaleOrderItemModel model where model.goodsId = ? and model.id = ?");
    List<SaleOrderItemModel> modelList = (List<SaleOrderItemModel>) this.hibernateTemplate.find(hql.toString(), goodsId,id);
    DownPurchaseOrderItem item = null;
    if (modelList != null && modelList.size() > 0) {
      for (SaleOrderItemModel itemModel : modelList) {
        item = new DownPurchaseOrderItem();
        ExtBeanUtils.copyProperties(itemModel, item);
      }
    }
    return item;
  }

  @Override
  public void generateStatement(DownPurchaseOrder order) {
    super.update(order);
  }

  /**
   * 上传单据图片
   *
   * @param order
   */
  @Override
  public void upload(DownPurchaseOrder order) {
    super.update(order);
  }

  @Override
  public void updateOrderAndItems(DownPurchaseOrder order) {
    SaleOrderModel orderModel = this.hibernateTemplate.get(SaleOrderModel.class, order.getId());
    if(orderModel == null){
      throw new DataModelException("订单不存在");
    }
    ExtBeanUtils.copyProperties(order, orderModel);
    this.hibernateTemplate.update(orderModel);
    //更新订单项
    order.getItems().forEach(orderItem -> {
      SaleOrderItemModel model = this.hibernateTemplate.get(SaleOrderItemModel.class, orderItem.getId());
      if(model == null){
        throw new DataModelException("对应明细不存在");
      }
      ExtBeanUtils.copyProperties(orderItem, model);
      this.hibernateTemplate.update(model);
    });
  }

  /**
   * 保存订单项方法
   *
   * @param saleOrderId
   * @param items
   */
  private void saveOrderItems(Long saleOrderId, List<DownPurchaseOrderItem> items) {
    items.stream().forEach(item -> {
      SaleOrderItemModel itemModel = new SaleOrderItemModel();

      GoodsModel goodsModel = this.hibernateTemplate.get(GoodsModel.class, item.getGoodsId());
      GoodsBrandModel goodsBrandModel = new GoodsBrandModel();
      if(goodsModel.getGoodsBrandId() != null){
        goodsBrandModel = this.hibernateTemplate.get(GoodsBrandModel.class, goodsModel.getGoodsBrandId());
      }
      GoodsCategoryModel goodsCategoryModel = new GoodsCategoryModel();
      if(goodsModel.getCategoryId() != null){
        goodsCategoryModel = this.hibernateTemplate.get(GoodsCategoryModel.class, goodsModel.getCategoryId());
      }

      SaleOrderModel saleOrderModel = this.hibernateTemplate.get(SaleOrderModel.class, saleOrderId);

      ExtBeanUtils.copyProperties(item, itemModel);
      itemModel.setSaleOrderId(saleOrderId);
      itemModel.setBusinessEntityId(saleOrderModel.getBusinessEntityId());
      //在仓储层冗余是为了安全和数据的准确
      itemModel.setGoodsName(goodsModel.getName());
      itemModel.setSpecName(goodsModel.getSpecName());
      itemModel.setGoodsCode(goodsModel.getCode());
      itemModel.setIsDefaultGoods(goodsModel.getIsDefaultGoods());
      itemModel.setConversionRate(goodsModel.getConversionRate());
      itemModel.setCodeBar(goodsModel.getCodeBar());
      itemModel.setUnits(goodsModel.getUnits());
      itemModel.setCategoryId(goodsModel.getCategoryId());
      itemModel.setCategoryName(goodsCategoryModel.getName());
      itemModel.setCategoryCatalogCode(goodsCategoryModel.getCatalogCode());
      itemModel.setGoodsBrandId(ExtStringUtils.isBlank(goodsModel.getGoodsBrandId()) ? null : goodsModel.getGoodsBrandId());
      itemModel.setGoodsBrandName(ExtStringUtils.isBlank(goodsBrandModel.getName()) ? null : goodsBrandModel.getName());
      this.hibernateTemplate.save(itemModel);
    });
  }

  /**
   * 删除订单项
   *
   * @param order
   */
  private void removeItem(DownPurchaseOrder order) {
    StringBuffer hql = new StringBuffer();
    hql.append("from SaleOrderItemModel model where model.saleOrderId = ?");
    List<SaleOrderItemModel> itemModelList = (List<SaleOrderItemModel>) this.hibernateTemplate.find(hql.toString(), order.getId());
    itemModelList.stream().forEach(item -> {
      this.hibernateTemplate.delete(item);
    });
  }

  /**
   * 根据id查找明细的方法
   *
   * @param id
   * @return
   */
  @Override
  public List<DownPurchaseOrderItem> getItemsByOrderId(Long id) {
    String hql = "from SaleOrderItemModel model where model.saleOrderId = ?";
    List<SaleOrderItemModel> itemModelList = (List<SaleOrderItemModel>) this.hibernateTemplate.find(hql, id);
    List<DownPurchaseOrderItem> itemList = new ArrayList<>();
    itemModelList.stream().forEach(itemMode -> {
      DownPurchaseOrderItem downPurchaseOrderItem = new DownPurchaseOrderItem();
      ExtBeanUtils.copyProperties(itemMode, downPurchaseOrderItem);
      itemList.add(downPurchaseOrderItem);
    });
    return itemList;
  }

  @Override
  public DonwPurchaseStatisticalAmountVo statisticalAmount(Wrapper we) {
    SQL sql = new SQL() {{
      SELECT(
              "SUM(downPurchaseOrder.TOTAL_AMOUNT) AS statisticalTotalAmount",
              "SUM(downPurchaseOrder.TOTAL_OUT_AMOUNT) AS statisticalTotalOutAmount"
      );
      FROM("T_SALE_ORDER downPurchaseOrder");
    }};
    StringBuffer sqlString = new StringBuffer(sql.toString());
    BaseResolve resolveToSQL = this.getViewWrapperResolve(we);
    sqlString.append(" WHERE 1 = 1").append(resolveToSQL.resolve());
    Map<String, Object> list = MybatisTemplate.selectOne(sqlString.toString());
    DonwPurchaseStatisticalAmountVo vo = JSONObject.parseObject(JSONObject.toJSONString(list), DonwPurchaseStatisticalAmountVo.class);
    return vo;
  }

  @Override
  public List<DonwPurchaseStatisticalAmountVo> statisticalAmountByMerchant(Wrapper we) {
    BaseResolve resolveToSQL = this.getViewWrapperResolve(we);
    SQL sql = new SQL() {{
      SELECT(
              "supplier.CODE AS merchantCode",
              "supplier.NAME AS merchantName",
              "SUM(downPurchaseOrder.TOTAL_AMOUNT) AS statisticalTotalAmount",
              "SUM(downPurchaseOrder.TOTAL_OUT_AMOUNT) AS statisticalTotalOutAmount"
      );
      FROM("T_SALE_ORDER downPurchaseOrder");
      INNER_JOIN("T_BASE_SUPPLIER supplier ON downPurchaseOrder.BUSINESS_ENTITY_ID = supplier.ID");
      WHERE(resolveToSQL.resolveQueryCondition());
      GROUP_BY("supplier.CODE","supplier.NAME");
      ORDER_BY("SUM(downPurchaseOrder.TOTAL_OUT_AMOUNT) DESC");
    }};
    StringBuffer sqlString = new StringBuffer(sql.toString());
    sqlString.append(" LIMIT 0,10");
    List<Map<String, Object>> list = MybatisTemplate.selectList(sqlString.toString());
    List<DonwPurchaseStatisticalAmountVo> vos = JSONArray.parseArray(JSONObject.toJSONString(list), DonwPurchaseStatisticalAmountVo.class);
    return vos;
  }

  @Override
  public List<DonwPurchaseStatisticalAmountVo> statisticalAmountByGoods(Wrapper we) {
    BaseResolve resolveToSQL = this.getViewWrapperResolve(we);
    SQL sql = new SQL() {{
      SELECT(
              "goods.CODE AS goodsCode",
              "goods.NAME AS goodsName",
              "SUM(saleItem.TOTAL_AMOUNT) AS statisticalTotalAmount",
              "SUM(saleItem.OUT_TOTAL_AMOUNT) AS statisticalTotalOutAmount"
      );
      FROM("T_SALE_ORDER downPurchaseOrder");
      INNER_JOIN("T_SALE_ORDER_ITEM saleItem ON downPurchaseOrder.ID = saleItem.SALE_ORDER_ID");
      INNER_JOIN("T_BASE_GOODS goods ON saleItem.GOODS_ID = goods.ID");
      WHERE(resolveToSQL.resolveQueryCondition());
      GROUP_BY("goods.CODE","goods.NAME");
      ORDER_BY("SUM(saleItem.OUT_TOTAL_AMOUNT) DESC");
    }};
    StringBuffer sqlString = new StringBuffer(sql.toString());
    sqlString.append(" LIMIT 0,10");
    List<Map<String, Object>> list = MybatisTemplate.selectList(sqlString.toString());
    List<DonwPurchaseStatisticalAmountVo> vos = JSONArray.parseArray(JSONObject.toJSONString(list), DonwPurchaseStatisticalAmountVo.class);
    return vos;
  }

  @Override
  protected SQL getViewSql() {
    return new SQL() {{
      SELECT(
              SQLAliasGenerateUtil.aliasGenerate(SaleOrderModel.class, "downPurchaseOrder", null),
              "supplier.NAME AS supplierName"
      );
      FROM("T_SALE_ORDER downPurchaseOrder");
      INNER_JOIN("T_BASE_SUPPLIER supplier on downPurchaseOrder.BUSINESS_ENTITY_ID = supplier.ID");
    }};
  }

  @Override
  protected Class getViewObject() {
    return DownPurchaseOrderVo.class;
  }

  @Override
  protected BaseResolve getViewWrapperResolve(Wrapper wrapper) {
    Map<String, String> params = new HashMap<>();
    params.put("businessEntityId", "downPurchaseOrder.DOWN_STREAM_COMPANY_ID");
    params.put("id", "downPurchaseOrder.ID");
    params.put("createdType", "downPurchaseOrder.CREATED_TYPE");
    params.put("deliName", "downPurchaseOrder.DELI_NAME");
    params.put("deliveryState", "downPurchaseOrder.DELIVERY_STATE");
    params.put("collectState", "downPurchaseOrder.COLLECT_STATE");
    params.put("ordState", "downPurchaseOrder.ORD_STATE");
    params.put("createTimeStamp", "downPurchaseOrder.CREATE_TIME_STAMP");
    params.put("code", "downPurchaseOrder.CODE");
    params.put("statementId", "downPurchaseOrder.STATEMENT_ID");
    params.put("logisticsCompanyId","downPurchaseOrder.LOGISTICS_COMPANY_ID");
    ResolveToSQL parse = new ResolveToSQL(wrapper, (propertyName) -> {
      return params.get(propertyName);
    });
    return parse;
  }

  /**
   * 内部方法  领域对象转vo
   *
   * @param entityList
   * @return
   */
  private List<DownPurchaseOrderItemVo> transformDownPurcharse(List<DownPurchaseOrderItem> entityList) {
    List<DownPurchaseOrderItemVo> voList = new ArrayList<>();
    entityList.stream().forEach((entity) -> {
      DownPurchaseOrderItemVo vo = new DownPurchaseOrderItemVo();
      ExtBeanUtils.copyProperties(entity, vo);
      voList.add(vo);
    });
    return voList;
  }
}
